package com.vr.cloudpicture.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vr.cloudpicture.exception.BusinessException;
import com.vr.cloudpicture.exception.ErrorCode;
import com.vr.cloudpicture.exception.ThrowUtils;
import com.vr.cloudpicture.mapper.SpaceMapper;
import com.vr.cloudpicture.model.dto.space.analyze.*;
import com.vr.cloudpicture.model.dto.user.UserLogin;
import com.vr.cloudpicture.model.entity.Picture;
import com.vr.cloudpicture.model.entity.Space;
import com.vr.cloudpicture.model.vo.analyze.*;
import com.vr.cloudpicture.service.IPictureService;
import com.vr.cloudpicture.service.ISpaceAnalyzeService;
import com.vr.cloudpicture.service.ISpaceService;
import com.vr.cloudpicture.service.IUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Space Analyze 服务实现
 *
 * @author hzh
 * @date 2025/05/24
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SpaceAnalyzeServiceImpl extends ServiceImpl<SpaceMapper, Space> implements ISpaceAnalyzeService {
    private final IPictureService pictureService;
    private final ISpaceService spaceService;
    private final IUserService userService;

    @Override
    public SpaceUsageAnalyzeResponse getSpaceUsageAnalyze(SpaceUsageAnalyzeRequest spaceUsageAnalyzeRequest, UserLogin loginUser) {
        Boolean queryPublic = spaceUsageAnalyzeRequest.getQueryPublic();
        Boolean queryAll = spaceUsageAnalyzeRequest.getQueryAll();
        ThrowUtils.throwIf(ObjUtil.isEmpty(queryPublic) || ObjUtil.isEmpty(queryAll), ErrorCode.PARAMS_ERROR);
        if (queryAll || queryPublic) {
            // 表示查询空间全部或者查询公共图库逻辑,只有管理员才能查询
            boolean admin = userService.isAdmin(loginUser);
            ThrowUtils.throwIf(!admin, ErrorCode.NOT_AUTH_ERROR, "无权限");
            // 统计公共图库资源
            LambdaQueryWrapper<Picture> queryWrapper = new LambdaQueryWrapper<>();
            // 只需要picSize,所以只查询这个字段，节省空间，减少内存消耗
            queryWrapper.select(Picture::getPicSize);
            if (!queryAll) {
                queryWrapper.isNull(Picture::getSpaceId);
            }
            // 直接拿到结果，不要picSize这个key，节省空间，如[12,34,..],如果不这样的话就是[{picSize:12},{picSize:34},...]
            List<Object> pictureObjectList = pictureService.getBaseMapper().selectObjs(queryWrapper);
            long usedSize = pictureObjectList.stream().mapToLong(obj -> obj instanceof Long ? (Long) obj : 0L).sum();
            long usedCount = pictureObjectList.size();

            // 封装返回结果
            // 不管是公共图库还是所有所有空间都是无上限的
            return SpaceUsageAnalyzeResponse.builder()
                    .usedSize(usedSize)
                    .usedCount(usedCount)
                    // 不管是公共图库还是所有所有空间都是无上限的
                    .maxSize(null)
                    .sizeUsageRatio(null)
                    .maxCount(null)
                    .countUsageRatio(null)
                    .build();
        } else {
            // 查询指定空间
            Long spaceId = spaceUsageAnalyzeRequest.getSpaceId();
            ThrowUtils.throwIf(ObjUtil.isEmpty(spaceId) || spaceId <= 0, ErrorCode.PARAMS_ERROR);
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(ObjUtil.isEmpty(space), ErrorCode.NOT_FOUND_ERROR, "空间不存在");
            // 权限校验，仅管理员或者空间所有者才能查询
            spaceService.checkSpaceAuth(space, loginUser);

            // 构建返回结果
            return SpaceUsageAnalyzeResponse.builder()
                    .usedSize(space.getTotalSize())
                    .maxSize(space.getMaxSize())
                    .sizeUsageRatio(NumberUtil.round(space.getTotalSize() * 100.0 / space.getMaxSize(), 2).doubleValue())
                    .usedCount(space.getTotalCount())
                    .maxCount(space.getMaxCount())
                    .countUsageRatio(NumberUtil.round(space.getTotalCount() * 100.0 / space.getMaxCount(), 2).doubleValue())
                    .build();
        }
    }

    @Override
    public List<SpaceCategoryAnalyzeResponse> getSpaceCategoryAnalyze(SpaceCategoryAnalyzeRequest spaceCategoryAnalyzeRequest, UserLogin loginUser) {
        // 检查权限
        checkSpaceAnalyzeAuth(spaceCategoryAnalyzeRequest, loginUser);
        // 构造查询条件
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        // 根据分析范围补充查询条件
        fillAnalyzeQueryWrapper(spaceCategoryAnalyzeRequest, queryWrapper);
        queryWrapper.select("category as category",
                        "count(*) as count",
                        "sum(pic_size) as totalSize")
                .groupBy("category");
        // 查询并转换
        return pictureService.getBaseMapper().selectMaps(queryWrapper)
                .stream()
                .map(itemMap -> {
                    String category = itemMap.get("category") != null ? itemMap.get("category").toString() : "未分类";
                    Long count = ((Number) itemMap.get("count")).longValue();
                    Long totalSize = ((Number) itemMap.get("totalSize")).longValue();
                    return SpaceCategoryAnalyzeResponse.builder()
                            .category(category)
                            .count(count)
                            .totalSize(totalSize)
                            .build();
                }).collect(Collectors.toList());
    }

    private void fillAnalyzeQueryWrapper(SpaceAnalyzeRequest spaceAnalyzeRequest, QueryWrapper<Picture> queryWrapper) {
        if (spaceAnalyzeRequest.getQueryAll()) {
            // 表示查询所有，那么啥都不用添加
            return;
        }
        if (spaceAnalyzeRequest.getQueryPublic()) {
            // 表示查询公共图库，那么就查询spaceId为null的
            queryWrapper.isNull("space_id");
            return;
        }
        // 查询指定空间
        if (spaceAnalyzeRequest.getSpaceId() != null) {
            queryWrapper.eq("space_id", spaceAnalyzeRequest.getSpaceId());
            return;
        }
        throw new BusinessException(ErrorCode.PARAMS_ERROR, "未指定查询范围");
    }

    @Override
    public void checkSpaceAnalyzeAuth(SpaceAnalyzeRequest spaceUsageAnalyzeRequest, UserLogin loginUser) {
        Long spaceId = spaceUsageAnalyzeRequest.getSpaceId();
        Boolean queryPublic = spaceUsageAnalyzeRequest.getQueryPublic();
        Boolean queryAll = spaceUsageAnalyzeRequest.getQueryAll();
        ThrowUtils.throwIf(ObjUtil.isEmpty(queryPublic) || ObjUtil.isEmpty(queryAll), ErrorCode.PARAMS_ERROR);
        if (queryAll || queryPublic) {
            // 查询全部空间或者公共图库，需要管理员权限
            boolean admin = userService.isAdmin(loginUser);
            ThrowUtils.throwIf(!admin, ErrorCode.NOT_AUTH_ERROR, "无权限");
        } else {
            // 查询指定空间，需要空间所有者或者管理员权限
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(ObjUtil.isEmpty(space), ErrorCode.NOT_FOUND_ERROR, "空间不存在");
            spaceService.checkSpaceAuth(space, loginUser);
        }
    }

    @Override
    public List<SpaceTagAnalyzeResponse> getSpaceTagAnalyze(SpaceTagAnalyzeRequest spaceTagAnalyzeRequest, UserLogin loginUser) {
        // 检查权限
        checkSpaceAnalyzeAuth(spaceTagAnalyzeRequest, loginUser);
        // 构造查询条件
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        // 根据分析范围补充查询条件
        fillAnalyzeQueryWrapper(spaceTagAnalyzeRequest, queryWrapper);
        // 查询所有符合的标签
        queryWrapper.select("tags");
        List<String> tagsJsonList = pictureService.getBaseMapper().selectObjs(queryWrapper)
                .stream()
                .filter(ObjUtil::isNotEmpty)
                .map(Object::toString)
                .collect(Collectors.toList());
        // 合并所有标签并统计
        Map<String, Long> tagCountMap = tagsJsonList.parallelStream()
                .flatMap(tagsJson -> JSONUtil.toList(tagsJson, String.class).stream())
                .collect(Collectors.groupingBy(tag -> tag, Collectors.counting()));
        // 转换成响应对象，按照count降序排序
        return tagCountMap.entrySet().stream()
                // 降序
                .sorted((e1, e2) -> Long.compare(e2.getValue(), e1.getValue()))
                .map(entry -> SpaceTagAnalyzeResponse.builder()
                        .tag(entry.getKey())
                        .count(entry.getValue())
                        .build()).collect(Collectors.toList());
    }

    @Override
    public List<SpaceSizeAnalyzeResponse> getSpaceSizeAnalyze(SpaceSizeAnalyzeRequest spaceSizeAnalyzeRequest, UserLogin loginUser) {
        // 检查权限
        checkSpaceAnalyzeAuth(spaceSizeAnalyzeRequest, loginUser);
        // 构造查询条件
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        // 根据分析范围补充查询条件
        fillAnalyzeQueryWrapper(spaceSizeAnalyzeRequest, queryWrapper);
        // 查询所有符合条件的图片大小
        queryWrapper.select("pic_size");
        List<Long> picSizeList = pictureService.getBaseMapper().selectObjs(queryWrapper)
                .parallelStream()
                    .map(size -> ((Number) size).longValue())
                .collect(Collectors.toList());
        // 定义分段范围，用有序的map
        LinkedHashMap<String, Long> sizeRangeMap = new LinkedHashMap<>();
        sizeRangeMap.put("<100KB", picSizeList.stream().filter(size -> size < 1024 * 100).count());
        sizeRangeMap.put("100KB-500KB", picSizeList.stream().filter(size -> size >= 1024 * 100 && size < 1024 * 500).count());
        sizeRangeMap.put("500KB-1MB", picSizeList.stream().filter(size -> size >= 1024 * 500 && size < 1024 * 1024).count());
        sizeRangeMap.put(">1MB", picSizeList.stream().filter(size -> size > 1024 * 1024).count());

        // 转换成响应对象，会按照map的顺序转成list
        return sizeRangeMap.entrySet().stream()
                .map(entry -> SpaceSizeAnalyzeResponse.builder()
                        .sizeRange(entry.getKey())
                        .count(entry.getValue())
                        .build())
                .collect(Collectors.toList());
    }

    @Override
    public List<SpaceUserAnalyzeResponse> getSpaceUserAnalyze(SpaceUserAnalyzeRequest spaceUserAnalyzeRequest, UserLogin loginUser) {
        // 检查权限
        checkSpaceAnalyzeAuth(spaceUserAnalyzeRequest, loginUser);
        // 构造查询条件
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        Long userId = spaceUserAnalyzeRequest.getUserId();
        queryWrapper.eq(userId != null, "user_id", userId);
        // 根据分析范围补充查询条件
        fillAnalyzeQueryWrapper(spaceUserAnalyzeRequest, queryWrapper);
        // 分析维度，每日、每周、每月
        String timeDimension = spaceUserAnalyzeRequest.getTimeDimension();
        switch (timeDimension) {
            case "day":
                queryWrapper.select("DATE_FORMAT(create_time,'%Y-%m-%d') as period", "count(*) as count");
                break;
            case "week":
                queryWrapper.select("YEARWEEK(create_time) as period", "count(*) as count");
                break;
            case "month":
                queryWrapper.select("DATE_FORMAT(create_time,'%Y-%m') as period", "count(*) as count");
                break;
            default:
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "不支持时间维度");
        }
        // 分组和排序
        queryWrapper.groupBy("period").orderByAsc("period");
        // 查询结果并转换
        return pictureService.getBaseMapper().selectMaps(queryWrapper)
                .stream()
                .map(itemMap -> {
                    String period = itemMap.get("period").toString();
                    long count = ((Number) itemMap.get("count")).longValue();
                    return new SpaceUserAnalyzeResponse(period, count);
                }).collect(Collectors.toList());
    }

    @Override
    public List<Space> getSpaceRankAnalyze(SpaceRankAnalyzeRequest spaceRankAnalyzeRequest, UserLogin loginUser) {
        // 构建条件
        QueryWrapper<Space> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id","space_name","user_id","total_size")
                .orderByDesc("total_size")
                .last("limit "+spaceRankAnalyzeRequest.getTopN());
        // 查询
        return spaceService.list(queryWrapper);
    }
}
